package com.sinosoft.hydra.um.utils;

import cn.com.sinux.spring.commons.SpringUtils;
import cn.com.sinux.spring.utils.CodeUtils;
import cn.com.sinux.spring.utils.CookieUtils;
import cn.com.sinux.spring.utils.RequestUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sinosoft.hydra.logging.LogModules;
import com.sinosoft.hydra.um.LoginUser;
import com.sinosoft.hydra.um.domain.permission.SysUserMember;
import com.sinosoft.hydra.um.helper.AuthContextHelper;
import com.sinosoft.hydra.um.services.SysUserService;
import com.sinosoft.hydra.um.shiro.UserRealm;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.subject.Subject;
import org.slf4j.LoggerFactory;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

//import com.sun.javafx.scene.control.skin.KeyCodeUtils;

/**
 * 应用的工具类-用于定义一些应用级的常量和方法
 */
public class AppUtils {

    public static final String TOKEN_COOKIE_NAME = "iPlanetDirectoryPro";
    public static final String TOKEN = "token";

    /**
     * For MD5,SHA-1,SHA-256
     *
     * @param plainText   待加密字符
     * @param encryptType 加密类型 16 或 32位加密 ，默认32位加密
     * @return 返回MD5加密后的字符
     */
    public static final String GetMD5(String plainText, Integer length, String encryptType) {
        String str = "";
        try {
            MessageDigest md = MessageDigest.getInstance(encryptType);
            md.update(plainText.getBytes());
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            if (length == 16) {
                str = buf.toString().substring(8, 24);// 16位的加密
            } else {
                str = buf.toString();// 32位的加密
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return str;
    }

    public enum OnlineCounter {
        INSTANCE;
        private int online = 0;
        public void login(){
            online++;
        }
        public void logout(){
            online--;
        }
        public int getOnline(){
            return online;
        }
    }


    /**
     * 解析页面传递的JsonList(eg:{ids:[1,2,3,4,5]})
     *
     * @param jsonList
     * @return
     */
    @SuppressWarnings("serial")
    public static List<String> parseJson2List(String jsonList) {
        List<String> ids = null;
        try {
            JSONObject jsonObject = JSONObject.parseObject(jsonList);
            final JSONArray jsonArray = jsonObject.getJSONArray("ids");
            jsonObject.getJSONArray("ids");
            ids = new ArrayList<String>() {
                {
                    for (Iterator<Object> ite = jsonArray.iterator(); ite.hasNext(); ) {
                        add(ite.next().toString());
                    }
                }
            };
        } catch (Exception ex) {
            LoggerFactory.getLogger(LogModules.STD_LOGGER).error("data convert failure");
        }
        return ids;
    }

    /**
     * 获取shiro的subject对象
     *
     * @return
     */
    public static Subject getSubject() {
        return SecurityUtils.getSubject();
    }


    public static void logout() {
        getSubject().logout();
        clearAllCachedAuthorizationInfo();
    }

    /**
     * 清楚授权缓存
     */
    public static void clearAllCachedAuthorizationInfo() {
        RealmSecurityManager securityManager = (RealmSecurityManager) SecurityUtils.getSecurityManager();
        UserRealm myReam = (UserRealm) securityManager.getRealms().iterator().next();
        myReam.clearAllCachedAuthorizationInfo();
    }

    private static SysUserMember _getUser() {
        if (SecurityUtils.getSubject() != null && AppUtils.getSubject().getPrincipal() != null) {
            try {
                String uid = (String) AppUtils.getSubject().getPrincipal();
                if (uid == null) {
                    //尝试从cookie中获取
                    return null;
                }
                return SpringUtils.getBean(SysUserService.class).findOne(uid);
            } catch (Exception ex) {
                return null;
            }
        }
        return null;
    }

    /**
     * 获取放在subject中的用户对象
     *
     * @return
     */
    public static LoginUser getUser() {
        return AuthContextHelper.getLoginUser();
    }

    /**
     * 获取当前登录用户的id
     *
     * @return
     */
    public static String getLoginUserId() {
        return (String)getSubject().getPrincipal();
    }

    public static void clearUserInfoInCookie(HttpServletResponse response) {
        CookieUtils.removeCookie(response, TOKEN_COOKIE_NAME);
    }

    public static SysUserMember getLoginUser(HttpServletRequest request) {
        String cacheKey = request.getParameter(TOKEN);
        if (StringUtils.isBlank(cacheKey)) {
            return null;
        }
        String loginName = CodeUtils.base64Decode(cacheKey);
        if (StringUtils.isBlank(loginName)) {
            return null;
        }
        return SpringUtils.getBean(SysUserService.class).doGetAuthenticationInfoByNumber(loginName);
    }


    public static LoginUser createLoginUser(HttpServletRequest request, HttpServletResponse response) {
        SysUserMember sysUserMember = _getUser();
        if (sysUserMember == null) {
            sysUserMember = getLoginUser(request);
        } else {
            String userNumber = sysUserMember.getUserNumber();
            int time = request.getSession().getMaxInactiveInterval() * 1000;
            Cookie cookie = CookieUtils.getCookie(request, TOKEN_COOKIE_NAME);
            if (cookie == null) {
                CookieUtils.setCookie(response, TOKEN_COOKIE_NAME, CodeUtils.base64Encode(userNumber), time);
            } else {
                cookie.setMaxAge(time);
            }
        }
        if (sysUserMember == null) {
            return null;
        }
        LoginUser loginUser = LoginUser.createLoginUser(sysUserMember);
        loginUser.setClientIp(RequestUtils.getClientIp(request));
        return loginUser;
    }
}
